package com.example.demo.service.impl;

import com.example.demo.pojo.Answer;
import com.example.demo.pojo.Subject;
import com.example.demo.pojo.Topic;
import com.example.demo.pojo.TopicOption;
import com.example.demo.service.SubjectService;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Field;
import com.mongodb.client.model.Filters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.Fields;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;

@Service("subjectServiceTemplate")
public class SubjectServiceImpl implements SubjectService {

    private static final Log log = LogFactory.getLog(SubjectServiceImpl.class);

    @Autowired
    MongoTemplate mongoOps;


    @Override
    public void addSubject(Subject subject) {
        mongoOps.insert(subject);
    }

    @Override
    public void addTopicToSubject(String subjectId, Topic topic) {
        topic.setSubjectId(subjectId);
        mongoOps.insert(topic);
    }

    @Override
    public List<Topic> findBySubject(String subjectId){
        List<Topic> result=mongoOps.query(Topic.class).matching(query(where("subjectId").is(subjectId))).all();
        return result;
    }

    @Override
    public void addTopicOptions(String optionId, TopicOption topicOption){
        topicOption.setTopicId(optionId);
        mongoOps.insert(topicOption);
    }

    @Override
    public void addAnswer(String oper, String topicId, String topicValue){
        Answer answer = new Answer();
        answer.setRegOper(oper);
        answer.setTopicId(topicId);
        answer.setTopicValue(topicValue);

        Optional<Topic> optional=mongoOps.query(Topic.class)
                .matching(query(where("id").is(topicId))).first();
        if (optional.isPresent()){
            Topic topic = optional.get();
            answer.setSubjectId(topic.getSubjectId());
            mongoOps.insert(answer);
        }else {
            throw new RuntimeException("topic does not exits "+topicId);
        }

    }

    /**
     *
     * @param subjectId
     * @return
     */
    /*db.subject.aggregate([
    {$project:{id:{ $toString: '$_id' },title:1}},
    {
        $lookup:
        {
            from: "topic",
                    localField: "id",
                foreignField: "subjectId",
                as: "topics"
        }
    },
    {$unwind:"$topics"},
    {
        $project:{

            title:1,
                    topics:{
                id:{$toString: '$topics._id'} ,
                name:1,
                        type:1,
                        order:1
            }
        }
    },
    {
        $lookup:
        {
            from: "topicOption",
                    localField: "topics.id",
                foreignField: "topicId",
                as: "topics.topicOptions"
        }
    },
    {
        $group:{
            _id:   "$_id",
                    title:{$first:'$title'},
            topics:{$push:'$topics'}
        }
    }
    ])*/
    @Override
    public Document getQuestionnaire(String subjectId){
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(where("_id").is(subjectId)),
                Aggregation.project("title").andExpression("toString(_id)").as("id"),
                Aggregation.lookup(Fields.field("topic"),Fields.field("id"),Fields.field("subjectId"),Fields.field("topics")),
                Aggregation.unwind("topics"),
                Aggregation.addFields().addField("topics.id").withValueOfExpression("toString(topics._id)").build(),
               /* Aggregation.project("title","topics.name","topics.type","topics.order")
                        .andExpression("toString(topics._id)").as("topics.id")*/
           /*     Aggregation.project("title","id")
                        .andExpression("toString(topics._id)").as("topics.id")
                        .and("topics.name").as("topics.name")
                        .and("topics.order").as("topics.order")
                        .and("topics.type").as("topics.type"),*/
                Aggregation.lookup("topicOption","topics.id","topicId","topics.topicOptions"),
                Aggregation.group("id").first("title").as("title").push("topics").as("topics")
        );
        log.info(aggregation.toString());
        AggregationResults<Document> results=mongoOps.aggregate(aggregation,"subject",Document.class);
        log.info(results.getMappedResults());
        return results.getMappedResults().get(0);
    }

   /* db.subject.aggregate([
    {$match:{_id:{$eq:ObjectId('5f363791badd872947095089')}}},
    {$addFields:{id:{ $toString: '$_id' }}},
    {
        $lookup:
        {
            from: "topic",
                    localField: "id",
                foreignField: "subjectId",
                as: "topics"
        }
    },
    {$unwind:"$topics"},
    {$addFields:{'topics.id':{ $toString: '$topics._id' }}},
    {
        $lookup:
        {
            from: "answer",
                    localField: "topics.id",
                foreignField: "topicId",
                as: "topics.answer"
        }
    }
    ])   ;*/
    @Override
    public List<Document> getQuestionnaireAnser(String subjectId){
//        client.
        MongoCollection<Document> collection= mongoOps.getCollection("subject");
        List<Document> results= new ArrayList<>();
        collection.aggregate(
                Arrays.asList(
                        Aggregates.match(Filters.eq("_id", new ObjectId(subjectId))),
                        Aggregates.addFields(new Field<>("id",new Document("$toString","$_id"))),
                        Aggregates.lookup("topic","id","subjectId","topics"),
                        Aggregates.unwind("$topics"),
                        Aggregates.addFields(new Field<>("topics.id",new Document("$toString","$topics._id"))),
                        Aggregates.lookup("answer","topics.id","topicId","topics.answer"),
                        Aggregates.group("$_id",Accumulators.first("title","$title"),
                                Accumulators.push("topics","$topics"))

                )
        ).forEach( t -> results.add(t));
        log.info(results);
        return results;
    }

    public static void main(String[] args) {
        Field<Document> field=new Field<>("topics.id",new Document("$toString","$'topics._id'"));
        log.info(field.getValue().toJson());
        Bson bson=Aggregates.addFields(field);
        log.info(bson.toString());
    }
}
